package cn.flying.cloud.task.core.scheduler;

import javax.annotation.Resource;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.configuration.JobLocator;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import cn.flying.cloud.base.common.utils.Ft;
import cn.flying.cloud.task.core.callback.disruptor.AsyncJobLogDisruptor;
import cn.flying.cloud.task.core.exception.TaskException;
import cn.flying.cloud.task.core.model.JobContext;
import cn.flying.cloud.task.core.model.JobResult;

/**
 * 调度Batch任务
 *
 * @author: admin
 * @date: 2024年01月29日 23:28
 * @version: 1.0
 */
@Component
public class SchedBatchJob {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private JobLauncher jobLauncher;
    @Resource
    private JobLocator jobLocator;
    @Resource
    private JobOperator jobOperator;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private AsyncJobLogDisruptor asyncJobLogDisruptor;

    /**
     * 执行批量任务
     *
     * @param context
     */
    @Async
    public void run(JobContext context) {
        JobResult result = new JobResult();
        result.setId(context.getLogId());
        result.setJobName(context.getJobName());
        result.setJobGroup(context.getJobGroup());
        result.setJobDesc(context.getJobDesc());

//        result.setStartTime(LocalDateTime.now());
        result.setTenantId(context.getTenantId());
        //获取批量任务
        Job job;
        try {
            job = jobLocator.getJob(context.getJobName());
            if (job == null) {
                job = (Job) applicationContext.getBean(context.getJobName());
            }
        } catch (NoSuchJobException e) {
            throw new TaskException("批量任务【" + context.getJobName() + "】不存在！", e);
        }
        Map<String, Object> param = Ft.JSON.parseToMap(context.getJobParam());
        // 通过参数来区分 JobInstance = Job + JobParameters
        JobParameters jobParameters = new JobParametersBuilder()
                .addString("description", context.getJobDesc())
                .addString("serialNo", (String) param.get("serialNo"))
                .addString("jobDate", (String) param.get("jobDate"))
                .addString("tenantId", context.getTenantId())
                .toJobParameters();

        try {
            result.setFireTime(LocalDateTime.now());
            // 启动执行批量任务
            JobExecution execution = jobLauncher.run(job, jobParameters);
            if (logger.isDebugEnabled()) {
                logger.debug("批量任务执行完毕，【{}】", execution);
            }
            result.setJobInstId(execution.getJobInstance().getInstanceId() + "");
            if (execution.getStatus().isUnsuccessful()) {
                // 执行失败
                result.setJobStatus("FAIL");
                List<Throwable> list = execution.getAllFailureExceptions();
                StringBuilder builder = new StringBuilder();
                for (Throwable throwable : list) {
                    builder.append(ExceptionUtils.getStackTrace(throwable));
                }

                result.setJobMsg(execution.getExitStatus() + "");
                result.setJobTrace(builder.toString());
            } else {
                // 执行成功
                result.setJobStatus("SUCCESS");
                result.setJobMsg("执行成功");
            }
        } catch (JobExecutionAlreadyRunningException e) {
            logger.error("批量任务已经在运行！", e);
            // 执行失败
            result.setJobStatus("FAIL");
            result.setJobMsg("批量任务已经在运行");
            result.setJobTrace(ExceptionUtils.getStackTrace(e));
        } catch (JobRestartException e) {
            logger.error("批量任务重启异常！", e);
            // 执行失败
            result.setJobStatus("FAIL");
            result.setJobMsg("批量任务重启异常");
            result.setJobTrace(ExceptionUtils.getStackTrace(e));
        } catch (JobInstanceAlreadyCompleteException e) {
            logger.error("批量任务已经完成！", e);
            // 执行失败
            result.setJobStatus("FAIL");
            result.setJobMsg("批量任务已经完成");
            result.setJobTrace(ExceptionUtils.getStackTrace(e));
        } catch (JobParametersInvalidException e) {
            logger.error("批量任务参数校验异常！", e);
            // 执行失败
            result.setJobStatus("FAIL");
            result.setJobMsg("批量任务参数校验异常");
            result.setJobTrace(ExceptionUtils.getStackTrace(e));
        } catch (Exception e) {
            logger.error("批量任务执行异常！", e);
            // 执行失败
            result.setJobStatus("FAIL");
            result.setJobMsg("批量任务执行异常！");
            result.setJobTrace(ExceptionUtils.getStackTrace(e));
        } finally {
            result.setEndTime(LocalDateTime.now());
            asyncJobLogDisruptor.publish("job", Ft.JSON.serializer(result));
        }
    }

//    /**
//     * 补偿重启批量任务
//     *
//     * @param context
//     */
//    @Async
//    public void resolve(JobContext context) {
//        JobResult result = new JobResult();
//        result.setId(context.getLogId());
//        result.setJobName(context.getJobName());
//        result.setJobGroup(context.getJobGroup());
//        result.setJobDesc(context.getJobDesc());
//
////        result.setStartTime(LocalDateTime.now());
//        result.setTenantId(context.getTenantId());
//        //获取批量任务
//        Job job;
//        try {
//            job = jobLocator.getJob(context.getJobName());
//            if (job == null) {
//                job = (Job) applicationContext.getBean(context.getJobName());
//            }
//        } catch (NoSuchJobException e) {
//            throw new TaskException("批量任务【" + context.getJobName() + "】不存在！", e);
//        }
//        Map<String, Object> param = Ft.JSON.parseToMap(context.getJobParam());
//        // 通过参数来区分 JobInstance = Job + JobParameters
//        JobParameters jobParameters = new JobParametersBuilder()
//                .addString("description", context.getJobDesc())
//                .addString("serialNo", (String) param.get("serialNo"))
//                .addString("jobDate", (String) param.get("jobDate"))
//                .addString("tenantId", context.getTenantId())
//                .toJobParameters();
//
//        try {
//            result.setFireTime(LocalDateTime.now());
//            // 启动执行批量任务
//            // JobInstance = Job + JobParameters
//            // 根据执行ID（上一次未完成的执行ID或者实例ID）查询Job和JobParameters参数信息，注意这个只能重启状态为未完成的，已经完成的如果需要重复执行，需要修改参数
//            Long restart = jobOperator.restart(33L);
//            result.setJobInstId(execution.getJobInstance().getInstanceId() + "");
//            if (execution.getStatus().isUnsuccessful()) {
//                // 执行失败
//                result.setJobStatus("FAIL");
//                List<Throwable> list = execution.getAllFailureExceptions();
//                StringBuilder builder = new StringBuilder();
//                for (Throwable throwable : list) {
//                    builder.append(ExceptionUtils.getStackTrace(throwable));
//                }
//
//                result.setJobMsg(execution.getExitStatus() + "");
//                result.setJobTrace(builder.toString());
//            } else {
//                // 执行成功
//                result.setJobStatus("SUCCESS");
//                result.setJobMsg("执行成功");
//            }
//        } catch (JobExecutionAlreadyRunningException e) {
//            logger.error("批量任务已经在运行！", e);
//            // 执行失败
//            result.setJobStatus("FAIL");
//            result.setJobMsg("批量任务已经在运行");
//            result.setJobTrace(ExceptionUtils.getStackTrace(e));
//        } catch (JobRestartException e) {
//            logger.error("批量任务重启异常！", e);
//            // 执行失败
//            result.setJobStatus("FAIL");
//            result.setJobMsg("批量任务重启异常");
//            result.setJobTrace(ExceptionUtils.getStackTrace(e));
//        } catch (JobInstanceAlreadyCompleteException e) {
//            logger.error("批量任务已经完成！", e);
//            // 执行失败
//            result.setJobStatus("FAIL");
//            result.setJobMsg("批量任务已经完成");
//            result.setJobTrace(ExceptionUtils.getStackTrace(e));
//        } catch (JobParametersInvalidException e) {
//            logger.error("批量任务参数校验异常！", e);
//            // 执行失败
//            result.setJobStatus("FAIL");
//            result.setJobMsg("批量任务参数校验异常");
//            result.setJobTrace(ExceptionUtils.getStackTrace(e));
//        } catch (Exception e) {
//            logger.error("批量任务执行异常！", e);
//            // 执行失败
//            result.setJobStatus("FAIL");
//            result.setJobMsg("批量任务执行异常！");
//            result.setJobTrace(ExceptionUtils.getStackTrace(e));
//        } finally {
//            result.setEndTime(LocalDateTime.now());
//            asyncJobLogDisruptor.publish("job", Ft.JSON.serializer(result));
//        }
//    }

    /**
     * 停止批量任务
     *
     * @param context
     */
    public void stop(JobContext context) {
        try {
            // 获取指定 Job 的所有正在运行的执行 ID
            Set<Long> executionIds = jobOperator.getRunningExecutions(context.getJobName());
            for (Long executionId : executionIds) {
                // 停止指定执行 ID 的 Job
                jobOperator.stop(executionId);
            }
        } catch (Exception e) {
            throw new TaskException("批量任务停止失败！", e);
        }
    }
}
